package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.filters.BlurFilter;
	import flash.geom.Point;
	import flash.geom.ColorTransform;
	import flash.display.BlendMode;
	import flash.events.MouseEvent;
	
	[SWF( backgroundColor='0x121212', frameRate='35', width='256', height='256')]

	public class Main extends Sprite
	{
		private const NUM_PIXELS: uint = 50000;
		private const COLOR_BACKGROUND: uint = 0x121212;
		private const GRAVITY: Number = .1;
		private const DAMP: Number = .94;
		private const MOUSE_RADIUS: Number = 64;
		private const MOUSE_RADIUS_POW2: Number = MOUSE_RADIUS * MOUSE_RADIUS;

		private const origin: Point = new Point();
		private const blur: BlurFilter = new BlurFilter( 2, 2, 2 );
		private const alphaTrans: ColorTransform = new ColorTransform( 1, 1, 1, 1, 0, 0, 0, -4 );
		
		private var pixels: Array;
		private var output: BitmapData;
		private var blurOut: BitmapData;
		private var fps: FPS;
		
		[Embed(source='flash.png' )] private const Image: Class;
		[Embed(source='pattern.gif' )] private const Pattern: Class;
		
		private const imageData: BitmapData = Bitmap( new Image() ).bitmapData;
		
		private var mouseDown: Boolean;
		
		public function Main()
		{
			graphics.beginBitmapFill( Bitmap( new Pattern() ).bitmapData );
			graphics.drawRect( 0, 0, 256, 256 );
			graphics.endFill();
			
			init();
		}
		
		private function init(): void
		{
			pixels = new Array();
			
			const w: int = stage.stageWidth;
			const h: int = stage.stageHeight;
			
			var ox: int = ( w - imageData.width ) >> 1;
			var oy: int = ( h - imageData.height ) >> 1;
			
			var x: int;
			
			for( var y: int = 0 ; y < imageData.height ; y++ )
			{
				for( x = 0 ; x < imageData.width ; x++ )
				{
					pixels.push( new Pixel( x + ox, y + oy, imageData.getPixel32( x, y ) ) );
				}
			}
			
			output = new BitmapData( w, h, true, 0 );
			addChild( new Bitmap( output ) );
			
			blurOut = new BitmapData( w, h, true, 0 );
			
			var blurBitmap: Bitmap = new Bitmap( blurOut );
			blurBitmap.blendMode = BlendMode.ADD;
			//blurBitmap.filters = [ blur ];
			addChild( blurBitmap );
			
			fps = new FPS()
			//addChild( fps );
			
			addEventListener( Event.ENTER_FRAME, onEnterFrame );
			
			//-- browser boost
			var timer: Timer = new Timer( 10, 0 );
			timer.addEventListener( TimerEvent.TIMER, onTimer );
			timer.start();
			
			stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown );
		}
		
		private function onTimer( event: TimerEvent ): void
		{
			//run();
		}
		
		private function onEnterFrame( event: Event ): void
		{
			run();
		}
		
		private function run(): void
		{
			output.lock();
			blurOut.lock();
			output.fillRect( output.rect, COLOR_BACKGROUND );
			//blurOut.fillRect( blurOut.rect, COLOR_BACKGROUND );
			
			const w: int = stage.stageWidth;
			const h: int = stage.stageHeight;
			
			var sx: Number;
			var sy: Number;
			var vx: Number;
			var vy: Number;
			var dx: Number;
			var dy: Number;
			var dd: Number;
			
			var intensity: Number;
			var a: int;
			var c: uint;

			const mx: Number = mouseX;
			const my: Number = mouseY;
			
			for each( var pixel: Pixel in pixels )
			{
				sx = pixel.sx;
				sy = pixel.sy;
				vx = pixel.vx;
				vy = pixel.vy;
				
				if( mouseDown )
				{
					dx = mx - sx;
					dy = my - sy;
					dd = dx * dx + dy * dy;
					
					if( dd < MOUSE_RADIUS_POW2 )
					{
						dd = Math.sqrt( dd );
						
						//dd = MOUSE_RADIUS - dd;
						
						dd *= 2;
	
						if( dd > 0 )
						{
							vx -= dx / dd;
							vy -= dy / dd;
						}
					}
				}
				
				dx = pixel.tx - sx;
				dy = pixel.ty - sy;
				
				vx += dx * .02;
				vy += dy * .02;
				
				vx *= DAMP;
				vy *= DAMP;
				
				sx += vx;
				sy += vy;
				
				dd = dx * dx + dy * dy;
				
				if( dd > .25 )
				{
					blurOut.setPixel32( sx + .5, sy + .5, pixel.color );
				}
				else
				{
					intensity = ( .25 - dd ) / .25;
					
					c = pixel.color;
					a = ( c >> 24 ) & 0xff;
					
					output.setPixel32( sx + .5, sy + .5, ( c & 0xffffff ) | ( ( a * intensity ) << 24 ) );
				}
				
				pixel.sx = sx;
				pixel.sy = sy;
				pixel.vx = vx;
				pixel.vy = vy;
			}
			
			blurOut.applyFilter( blurOut, blurOut.rect, origin, blur );
			blurOut.colorTransform( blurOut.rect, alphaTrans );
			
			output.unlock();
			blurOut.unlock();
			
			fps.nextFrame();
		}
		
		private function onMouseDown( event: MouseEvent ): void
		{
			stage.addEventListener( MouseEvent.MOUSE_UP, onStageMouseUp );
			mouseDown = true;
		}
		private function onStageMouseUp( event: MouseEvent ): void
		{
			stage.removeEventListener( MouseEvent.MOUSE_UP, onStageMouseUp );
			mouseDown = false;
		}
	}
}
